
#pragma once

#include <vector>

#include <WinDef.h>

#include "Shaders\GBufferShader.h"
#include "Tools\Size.h"

class Camera;
class DeferredLightingShader;
class GBufferShader;
class HDRShader;
class Input;
class Light;
class MPMLShader;
class Scene;
class SPMLShader;
class Renderer;
class RenderTarget;
class RT2ScreenShader;

class Engine
{
public:
	// Singleton.
	//-----------------------------------------------
	static Engine& GetInstance();

	// Initialization & termination.
	//-----------------------------------------------
	BOOL IsValid() CONST;

	BOOL Initialize();
	VOID Terminate();

	// Getters.
	//-----------------------------------------------
	static UINT GetUpdateDelay();

	CONST Camera& camera() CONST;

	Size GetSize() CONST;

	// Execution.
	//-----------------------------------------------
	VOID Run();

protected:
	Engine();
	~Engine();

	Engine(CONST Engine&);
	Engine& operator = (CONST Engine&);

private:
	BOOL InitializeWindows();
	VOID TerminateWindows();
	
	BOOL InitializeScene();
	VOID TerminateScene();

	BOOL InitializeShaders();
	VOID TerminateShaders();

	BOOL InitializeExtras();
	VOID TerminateExtras();

	BOOL Update();
	BOOL Render() CONST;

	BOOL RenderSPML() CONST;
	BOOL RenderMPML() CONST;
	BOOL RenderDeferred() CONST;

	typedef enum
	{
		SPML,
		MPML,
		DEFERRED_RENDERING,
		MAX_RENDER_TYPE
	} RenderType;

	typedef enum
	{
		POSITIONS,
		DIRECTIONS,
		NORMALS,
		AMBIENT,
		DIFFUSE,
		SPECULAR,
		SHININESS,
		COMPOSITION,
		MAX_DEFERRED_RT
	} DeferredRenderingTarget;

	// Attributes.
	//-----------------------------------------------
	// Singleton.
	static Engine*			s_engine_instance;

	// Windows
	LPCTSTR					m_app_name;
	HINSTANCE				m_app_instance;
	HWND					m_app_window;

	Size					m_window_size;
	
	// Loop.
	static UINT             s_loop_delay;
	UINT					m_fps;

	// Managers.
	Renderer*				m_renderer;
	Input*					m_input;

	// Rendering.
	RenderType				m_render_type;

	BOOL					m_hdr;
	RenderTarget*			m_hdr_target;

	RenderTarget*			m_gbuffer[GBUFFER_RT_COUNT];
	DeferredRenderingTarget m_rt;

	SPMLShader*				m_spml_shader;
	MPMLShader*				m_mpml_shader;
	GBufferShader*			m_gbuffer_shader;
	DeferredLightingShader* m_deflight_shader;
	RT2ScreenShader*		m_rt2screen_shader;

	HDRShader*				m_hdr_shader;

	// Scene.
	Camera*					m_camera;
	Scene*					m_scene;

	// Flags.
	BOOL					m_initialized;
};

static LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam);
